//#include <isa.h>
#include "common.h"
#include <cstdlib>
//#include <memory/host.h>
//#include <memory/vaddr.h>
#include "map.h"
#include "host.h"

#define IO_SPACE_MAX (2 * 1024 * 1024)
void sdb_exit();
static uint8_t *io_space = NULL;
static uint8_t *p_space = NULL;

//should define in vaddr.h but it haven't be realized yet
#define PAGE_SHIFT 12
#define PAGE_SIZE (1ul << PAGE_SHIFT)
#define PAGE_MASK (PAGE_SIZE-1)
uint8_t* new_space(int size) {
  uint8_t *p = p_space;
  //page aligned;
  size = (size + (PAGE_SIZE - 1)) & ~PAGE_MASK;
  p_space += size;
  assert(p_space - io_space < IO_SPACE_MAX);
  return p;
}

static void check_bound(IOMap *map, paddr_t addr) {
	//printf("addr = %lx\n",addr);
  if (map == NULL) {
	//	npc_state.state = NPC_ABORT;
		sdb_exit();
		assert(map !=NULL);
    //Assert(map != NULL, "address (" FMT_PADDR ") is out of bound at pc = " FMT_WORD, addr, cpu.pc);
  } else {
    assert(addr <= map->high && addr >= map->low);
    //Assert(addr <= map->high && addr >= map->low,
    //    "address (" FMT_PADDR ") is out of bound {%s} [" FMT_PADDR ", " FMT_PADDR "] at pc = " FMT_WORD,
    //    addr, map->name, map->low, map->high, cpu.pc);
  }
}

static void invoke_callback(io_callback_t c, paddr_t offset, int len, bool is_write) {
  if (c != NULL) { c(offset, len, is_write); }
}
void *trm;
void init_map() {
	trm = malloc(IO_SPACE_MAX);	
	io_space = (uint8_t*)trm;
  assert(io_space);
  p_space = io_space;
}

word_t map_read(paddr_t addr, int len, IOMap *map) {
  assert(len >= 1 && len <= 8);
	//printf("%x,%d\n",addr,len);
  check_bound(map, addr);
  paddr_t offset = addr - map->low;
  invoke_callback(map->callback, offset, len, false);  //prepare data to read
  word_t ret = host_read((void*)((uint8_t*)map->space + offset), len);
#ifdef CONFIG_DTRACE
	Log("read %s\t address:%lx\t len:%d\t data:%lx",map->name,addr,len,ret);
#endif
  return ret;
}

void map_write(paddr_t addr, int len, word_t data, IOMap *map) {
  assert(len >= 1 && len <= 8);
  check_bound(map, addr);
  paddr_t offset = addr - map->low;
//	printf("\n1 = %lx,2 = %d,3 = %lx\n",map->space+offset,len,data);
  host_write((void*)((uint8_t*)map->space + offset), len, data);
  invoke_callback(map->callback, offset, len, true);
#ifdef CONFIG_DTRACE
	Log("write %s\t address:%lx\t len:%d\t data:%lx",map->name,addr,len,data);
#endif
}
